#include "pt.h"
#include "ptdebug.h"
#include "softirq.h"
#include "pt_mem.h"


static void tasklet_action(struct softirq_action *a);

static struct softirq_action softirq_vec[SOFTIRQ_MAX] = {
    [TASKLET].action = tasklet_action,
};  // 软中断表
static uint8_t softirq_pending_mask;                    // 软中断唤起标志集

static inline int32_t set_softirq_pending(uint8_t softirq_num)
{
    if( softirq_pending_mask & (1 << softirq_num) ){
        return -PT_EBUSY;
    }

    softirq_pending_mask |= ( 1 << softirq_num);

    return PT_EOK;
}
static inline int32_t clr_softirq_pending(void)
{

    softirq_pending_mask = 0;

    return PT_EOK;
}

static inline uint8_t get_softirq_pending(void)
{
    return softirq_pending_mask;
}

/**
 *@description: 设置平台相关的软中断唤起函数
 *@param: NA
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-05-01 19:54:45
*/
void (*swi_pending)(void);
void set_swi_pending( void (*cpu_swi_pending)(void) )
{
    swi_pending = cpu_swi_pending;
}

/**
 *@description: 唤起软中断
 *@param: softirq_num, 软中断号
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-05-01 18:47:18
*/
int32_t raise_softirq(uint8_t softirq_num)
{
    // 将相应位置位, 若未被置位返回PT_EOK
    if(PT_EOK == set_softirq_pending(softirq_num) ){
         swi_pending();   // 与硬件平台相关1
        return PT_EOK;
    }else{
        PT_DEBUG_LOG(PT_LOG_LEVEL_KERNEL, ("reraise softirq\n") );
        return -PT_EBUSY;
    }
}

/**
 *@description: 执行软中断, 轮询唤起的软中断并执行
 *@param: NA
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-05-01 19:31:00
*/
void do_softirq(void)
{
    uint8_t pending = 0xFF & get_softirq_pending();

    if(pending){
        struct softirq_action *h = softirq_vec;     // 指向软中断表头

        do{
            if(h->action != PT_NULL){
                h->action(h);
            }
            h++;                // 指向下一个软中断
            pending >>= 1;
        } while(pending);

    }

    clr_softirq_pending();
}

/**
 *@description: 注册应用程序提供的软中断回调函数
 *@param: nr, 软中断号, action, 回调函数
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-05-01 19:32:06
*/
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
	softirq_vec[nr].action = action;
}

void softirt_pass_params(int nr, void *data, uint32_t len)
{
    softirq_vec[nr].data = data;
    softirq_vec[nr].len = len;
}

// tasklet头部;
struct tasklet_struct tasklet_vec = {
    .list.next = &tasklet_vec.list,     // 链表初始化指向自己
    .list.prev = &tasklet_vec.list,

    .state = 0,                         // 无状态
    .count = 0,                         // 使能
    .func = PT_NULL,
    .data = PT_NULL,
    .len = 0,
};

/**
 *@description: tasklet轮询函数
 *@param: a, tasklet的软中断实例
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-05-01 21:25:16
*/
static void tasklet_action(struct softirq_action *a)
{
    (void)a;
    struct tasklet_struct *cur_tasklet;
    pt_list_t *temp = &tasklet_vec.list;

    //轮询tasklet列表
    do{
        cur_tasklet = pt_list_entry(temp, struct tasklet_struct, list);

        // 被调度后才执行
        if(cur_tasklet->state == TASKLET_STATE_SCHED){
            cur_tasklet->state = TASKLET_STATE_RUN;
            if(cur_tasklet->func != PT_NULL){
                cur_tasklet->func(cur_tasklet->data, cur_tasklet->len);
            }

            temp = temp->next;
            pt_list_remove(&cur_tasklet->list);
            cur_tasklet->state = TASKLET_STATE_READY;
        }else{
            temp = temp->next;
        }



    }while(temp != &tasklet_vec.list);
//    PT_DEBUG_LOG(PT_LOG_LEVEL_KERNEL, ("tasklet_action EXIT\n"));
}

void tasklet_schedule(struct tasklet_struct *t)
{

//	struct tasklet_head *head;
//	head = this_cpu_ptr(headp);
//	t->next = NULL;
//	*head->tail = t;
//	head->tail = &(t->next);
//	raise_softirq(softirq_nr);

	if(t->state == TASKLET_STATE_RUN || t->state == TASKLET_STATE_SCHED){
        return;
	}

	t->state = TASKLET_STATE_SCHED;

	pt_list_insert_after(&tasklet_vec.list, &t->list);

	raise_softirq(TASKLET);
}

void tasklet_init(struct tasklet_struct *t, void (*func)(void *data, uint32_t len))
{
    // 初始化的时候如果链表前后指向没有初始化, 则指向自己, 这样做防止在中途又重复初始化, 把链表破坏了
    if(t->list.next == PT_NULL || t->list.prev == PT_NULL){
        t->list.next = &t->list;
        t->list.prev = &t->list;
    }
	t->state = 0;
	t->count = 0;
	t->func = func;
}
#ifdef PT_USING_MEM_HEAP
struct tasklet_struct *tasklet_create(void (*func)(void *data, uint32_t len))
{
    struct tasklet_struct *t;

    t = kernel_malloc( sizeof(struct tasklet_struct) );

    if(t != PT_NULL){
        t->list.next = &t->list;
        t->list.prev = &t->list;
        t->state = 0;
        t->count = 0;
        t->func = func;

        return t;
    }

    return PT_NULL;

}
#endif // PT_USING_MEM_HEAP

void tasklet_pass_params(struct tasklet_struct *t, void *data, uint32_t len)
{
    t->data = data;
    t->len = len;
}
